Skip to content

[FEAT] 공통 캘린더 컴포넌트 구현#119

Merged
yumin-kim2 merged 10 commits into
developfrom
feat/ui/107-calendar-component
Jul 8, 2026
Merged

[FEAT] 공통 캘린더 컴포넌트 구현#119
yumin-kim2 merged 10 commits into
developfrom
feat/ui/107-calendar-component

Conversation

@yumin-kim2

@yumin-kim2 yumin-kim2 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

ISSUE 🔗

close #107



What is this PR? 🔍

디자인 시스템에 날짜 선택이 가능한 Calendar 공통 컴포넌트를 추가했습니다.

이번 작업은 단순히 캘린더 UI를 하나 그리는 것보다, “이걸 라이브러리로 가져갈지, 직접 구현할지”를 고민하면서 진행했습니다.

왜 직접 구현했는지

처음에는 react-day-picker 같은 캘린더 라이브러리를 도입하는 것도 고려했습니다.
다만 지금 필요한 기능은 날짜 선택, 월 이동, 오늘 날짜 표시, 이전/다음 달 날짜 흐리게 표시 정도였습니다.

반대로 디자인 요구사항은 꽤 구체적이었습니다.

  • 캘린더 전체 크기
  • 내부 padding
  • 날짜 간 gap
  • 선택 날짜의 blue background
  • 오늘 날짜의 bold text
  • 이전/다음 달 날짜의 연한 색상
  • 기존 WeeklyButton과 동일한 월 이동 버튼

이 정도 요구사항이면 라이브러리의 DOM 구조와 스타일을 덮어쓰는 비용이 더 커질 수 있다고 판단했습니다.
그래서 이번에는 외부 라이브러리 없이, 필요한 범위만 직접 구현하는 방향으로 결정했습니다.

날짜 그리드 계산

캘린더에서 제일 먼저 정리한 부분은 “이번 달 날짜만 1일부터 31일까지 보여주면 되는가?”였습니다.
실제로는 캘린더 첫 칸이 항상 1일이 아닙니다.
예를 들어 2026년 6월은 1일이 월요일이라, 첫 칸에는 5월 31일이 들어가야 합니다.
그래서 현재 월의 1일 요일을 기준으로 캘린더 시작 날짜를 계산하고, 그 날짜부터 순서대로 날짜 데이터를 만들었습니다.

const firstDate = new Date(year, monthIndex, 1);
const firstDay = firstDate.getDay();
const startDate = new Date(year, monthIndex, 1 - firstDay);

이렇게 하면 1일이 월요일인 달은 하루 전인 일요일부터, 1일이 수요일인 달은 사흘 전인 일요일부터 캘린더를 시작할 수 있습니다.

Figma 간격을 맞추면서 겪은 점

레이아웃을 맞추는 과정에서 가장 헷갈렸던 부분은 gap 기준이었습니다.
Figma에서 글자 자체 사이의 간격과, 글자를 감싸는 셀 기준의 간격이 다르게 보였습니다.
처음에는 날짜 텍스트 각각에 고정 크기를 주려고 했지만, 그러면 텍스트 기준과 셀 기준이 섞여서 오히려 맞추기 어려웠습니다.
그래서 최종적으로는 캘린더 전체 너비를 고정하고, 내부 padding과 grid gap을 기준으로 배치했습니다.
날짜 텍스트는 셀 안에서 중앙 정렬되도록 두고, 개별 텍스트마다 억지로 너비를 맞추지는 않았습니다.

flowchart LR
  A["Figma 간격 확인"] --> B{"기준 선택"}

  B --> C["글자 기준"]
  C --> C1["텍스트마다 크기 고정"]
  C1 --> C2["셀 기준과 섞임"]

  B --> D["셀 기준"]
  D --> D1["전체 width + padding"]
  D1 --> D2["grid gap"]
  D2 --> E["채택"]
Loading

또 하나의 트러블은 h-full이었습니다.
grid에 h-full을 주면 부모 높이를 전부 채우려 하면서 하단 날짜가 컨테이너 밖으로 밀리는 문제가 있었습니다.
그래서 grid는 필요한 만큼의 높이만 가지도록 두고, 캘린더 컨테이너의 고정 크기와 padding 안에서 정렬되도록 조정했습니다.

기존 버튼 재사용

월 이동 버튼은 새로 만들지 않고 기존 WeeklyButton을 재사용했습니다.

<WeeklyButton
  variant="left"
  onClick={() => moveMonth(-1)}
/>

<WeeklyButton
  variant="right"
  onClick={() => moveMonth(1)}
/>

선택 날짜와 오늘 날짜

선택 날짜와 오늘 날짜는 비슷해 보이지만 다른 상태라서 분리해서 계산했습니다.

  • isSelected: 사용자가 선택한 날짜
  • isToday: 실제 오늘 날짜
    처음에는 “선택된 날짜인지 확인하는 함수도 prop으로 받아야 하나?”를 고민했지만, 현재 구조에서는 value가 선택 날짜의 기준이기 때문에 Calendar 내부에서 isSelected를 계산하는 게 더 단순했습니다.
    사용처는 value와 onChange만 관리하고, 어떤 날짜가 선택되었는지는 Calendar가 판단합니다.

날짜 칸 수를 동적으로 계산한 이유

캘린더를 만들면서 35칸으로 고정할지, 42칸으로 고정할지 고민했습니다.

처음에는 Figma 기준이 5주 형태에 가까워 보여서 35칸으로 시작했습니다.
하지만 2026년 8월처럼 1일이 토요일이고 31일까지 있는 달은 5주 안에 모든 날짜가 들어가지 않습니다.

S  M  T  W  T  F  S
26 27 28 29 30 31 1
2  3  4  5  6  7  8
9  10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1  2  3  4  5

이런 달은 실제로 6주가 필요하기 때문에, 모든 달을 35칸으로 고정하면 마지막 주 날짜가 잘릴 수 있습니다.
그래서 현재 월의 시작 요일과 마지막 날짜를 기준으로 필요한 칸 수를 계산하도록 변경했습니다.

const lastDate = new Date(year, monthIndex + 1, 0);
const lastDay = lastDate.getDate();

const calendarCellCount = firstDay + lastDay > 35 ? 42 : 35;

firstDay + lastDay는 “이전 달 날짜로 채워야 하는 칸 수 + 이번 달 날짜 수”를 의미합니다.
이 값이 35를 넘으면 5주 안에 표시할 수 없기 때문에 42칸을 사용하고, 그렇지 않으면 35칸을 사용합니다.
이렇게 하면 5주로 충분한 달은 기존처럼 5주로 표시하고, 6주가 필요한 달만 한 줄 더 렌더링할 수 있습니다.



To Reviewers

Calendar를 외부 라이브러리로 만들지 않고 직접 구현한 이유는 현재 요구사항이 날짜 선택과 월 이동 중심으로 작고, Figma 디자인과 디자인 시스템 토큰을 맞추는 비중이 더 컸기 때문입니다.
특히 아래 지점을 중점적으로 봐주시면 좋겠습니다.

  • CalendarProps가 현재 사용처에서 충분한지 확인 부탁드립니다.
  • 5현재는 모든 달을 42칸으로 고정하지 않고, 5주로 충분한 달은 35칸, 6주가 필요한 달은 42칸으로 렌더링하도록 했습니다.



Screenshot 📷



2026-07-08.6.47.27.mov

Test Checklist ✔

  • pnpm lint
  • Calendar Storybook 스토리 추가
  • Storybook에서 날짜 선택 스타일 확인
  • 이전/다음 월 이동 버튼 동작 확인
  • 오늘 날짜와 선택 날짜 스타일 확인

@yumin-kim2 yumin-kim2 linked an issue Jul 7, 2026 that may be closed by this pull request
7 tasks
@vercel

vercel Bot commented Jul 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
timo Ready Ready Preview, Comment Jul 8, 2026 12:55pm

@github-actions github-actions Bot added the ⌚ Timo-Design-system Timo 디자인 시스템 label Jul 7, 2026
@github-actions github-actions Bot added ✨ Feature 새로운 기능(기능성) 구현 ♣️ 유민 유민양 labels Jul 7, 2026
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@yumin-kim2, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 30 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d92edb29-5f3f-403b-9ea2-b91df729aea0

📥 Commits

Reviewing files that changed from the base of the PR and between 297fa69 and 4e0e1ec.

📒 Files selected for processing (5)
  • apps/timo-web/components/layout/header/Header.tsx
  • packages/timo-design-system/src/components/button/chevron-button/ChevronButton.stories.tsx
  • packages/timo-design-system/src/components/button/chevron-button/ChevronButton.tsx
  • packages/timo-design-system/src/components/calendar/Calendar.tsx
  • packages/timo-design-system/src/components/index.ts

Walkthrough

디자인 시스템에 Calendar 컴포넌트와 Storybook 스토리가 추가되었습니다. 날짜 셀 생성, 선택 상태 처리, 월/연 헤더 렌더링, value/onChange 연결, barrel export, 버튼 스토리 경로 갱신이 포함됩니다.

Changes

Calendar 컴포넌트 구현

Layer / File(s) Summary
날짜 계산과 공개 타입
packages/timo-design-system/src/components/calendar/Calendar.tsx
WEEKDAYS, MONTH_LABELS, CalendarDate, getCalendarDates, CalendarProps가 추가되어 달력 데이터와 외부 입력 형태가 정의됩니다.
Calendar 상태와 렌더링
packages/timo-design-system/src/components/calendar/Calendar.tsx
기준 월 상태, 월 이동 처리, 요일 헤더, 날짜 버튼 렌더링, 오늘/선택 상태 스타일, onChange 호출이 추가됩니다.
스토리와 barrel export
packages/timo-design-system/src/components/calendar/Calendar.stories.tsx, packages/timo-design-system/src/components/index.ts, packages/timo-design-system/src/components/button/chevron-button/ChevronButton.stories.tsx
Default Storybook 스토리, CalendarWeeklyButton 재-export 변경, ChevronButton 스토리 경로/제목 갱신이 추가됩니다.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CalendarDemo
  participant Calendar
  participant WeeklyButton
  User->>WeeklyButton: 이전/다음 월 클릭
  WeeklyButton->>Calendar: onClick 실행
  Calendar->>Calendar: visibleMonth 갱신 및 날짜 재계산
  User->>Calendar: 날짜 셀 클릭
  Calendar->>CalendarDemo: onChange(date) 호출
  CalendarDemo->>Calendar: value 갱신
Loading

Possibly related PRs

  • Team-Timo/Timo-client#89: Calendar가 사용하는 WeeklyButton 재-export와 버튼 컴포넌트 경로 변경이 맞닿아 있습니다.

Suggested labels: ♦️ 민아

Suggested reviewers: ehye1, kimminna

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning [#107] Calendar 구현은 대체로 맞지만 월 이동 핸들러 참조 오류로 핵심 요구사항인 월 이동이 정상 동작하지 않을 수 있습니다. 월 이동 버튼의 핸들러를 실제 구현된 함수로 연결하고 빌드/린트를 다시 확인하세요. React 훅과 상태 관리 패턴은 공식 문서도 함께 점검하면 좋습니다.
✅ Passed checks (4 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed Storybook 추가와 export 경로 조정은 Calendar 도입에 필요한 범위 안에 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed 제목이 공통 캘린더 컴포넌트 추가라는 핵심 변경을 정확하고 간결하게 요약합니다.
Description check ✅ Passed 설명이 Calendar 추가, 스토리북 등록, export, 구현 이유까지 PR 변경과 잘 맞습니다.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ui/107-calendar-component

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

Storybook Preview

항목 링크
Storybook 열기
Chromatic 빌드 확인

마지막 업데이트: 2026-07-08 12:56 UTC

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

Timo Performance Report

Bundle Size — timo-web
라우트 크기 First Load JS
/[locale] 0 B 🟡 205.78 kB
/[locale]/focus 0 B 🟡 205.78 kB
/[locale]/home 0 B 🟡 205.78 kB
/[locale]/onboarding 0 B 🟡 205.78 kB
/[locale]/settings 0 B 🟡 205.78 kB
/[locale]/settings/account 0 B 🟡 205.78 kB
/[locale]/settings/policy 0 B 🟡 205.78 kB
/[locale]/statistics 0 B 🟡 205.78 kB
/[locale]/today 0 B 🟡 205.78 kB

공유 번들: 205.78 kB
🟢 < 200kB  |  🟡 < 350kB  |  🔴 ≥ 350kB (First Load JS · gzip)

Lighthouse — timo-web

⚠️ Lighthouse 결과를 가져오지 못했습니다.

Image Optimization — timo-web

public/ 디렉토리에 이미지가 없습니다.

측정 커밋: 35a1f36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/timo-design-system/src/components/calendar/Calendar.stories.tsx`:
- Around line 19-32: In CalendarDemo, the initial selectedDate and defaultMonth
point to different months, so the selected day is not visible when the story
opens. Update the story so Calendar’s value and defaultMonth are in the same
month, using the existing CalendarDemo, selectedDate, and CalendarProps setup so
the selection styling can be seen immediately in the default story.

In `@packages/timo-design-system/src/components/calendar/Calendar.tsx`:
- Around line 8-21: The MONTH_LABELS constant in Calendar is hardcoded to
English month names, so update the month label rendering to be locale-aware
using Intl.DateTimeFormat (or confirm English is intentionally required by the
design). Adjust the Calendar component to derive month names from the active
locale instead of relying on the static MONTH_LABELS array.
- Around line 3-4: Replace the relative imports in Calendar with absolute
imports by updating the `cn` and `WeeklyButton` imports to use the project’s
absolute path alias instead of `../../lib` and
`../button/weekly-button/WeeklyButton`. Keep the `Calendar` component unchanged
otherwise and ensure the new import paths resolve to the same modules via the
existing absolute path convention.
- Around line 119-142: `Calendar`의 날짜 버튼 클릭 처리에서 다른
달(`calendarDate.isCurrentMonth === false`) 날짜를 눌렀을 때도 현재 보이는 달이 바뀌도록 수정하세요.
`calendarDates.map` 안의 `button` `onClick`에서 `onChange` 호출 후, 선택한
`calendarDate.date`의 월을 기준으로 `visibleMonth`를 갱신하거나 부모로 월 변경 이벤트를 함께 전달하는 방식으로
연결하면 됩니다. `isCurrentMonth`, `onChange`, `visibleMonth`가 이 동작을 제어하는 핵심이니, 흐리게 표시된
날짜 클릭 시 해당 월로 자동 이동하도록 처리하세요.
- Around line 64-66: The visibleMonth state in Calendar is initialized only once
with useState(defaultMonth ?? value ?? new Date()), so it does not follow later
controlled value updates. Update Calendar so visibleMonth stays in sync when the
value prop changes, for example by adding a useEffect in Calendar.tsx that
watches value and updates setVisibleMonth accordingly while preserving
defaultMonth behavior. Use the Calendar and visibleMonth state in
packages/timo-design-system/src/components/calendar/Calendar.tsx to locate the
fix.
- Around line 29-49: The fixed 35-item range in getCalendarDates is truncating
months that require 6 weeks. Update Calendar.tsx so getCalendarDates generates
42 dates instead of 35, and make sure the calendar grid logic in Calendar and
WEEKDAYS stays separated so the header row does not reduce the visible date
slots. Keep the existing date calculation and isCurrentMonth behavior, just
extend the range to cover the full month display.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3c4ab145-16b2-4b5f-8105-74310a0f569a

📥 Commits

Reviewing files that changed from the base of the PR and between cf96425 and 0c11d89.

📒 Files selected for processing (3)
  • packages/timo-design-system/src/components/calendar/Calendar.stories.tsx
  • packages/timo-design-system/src/components/calendar/Calendar.tsx
  • packages/timo-design-system/src/components/index.ts

Comment on lines +3 to +4
import { cn } from "../../lib";
import { WeeklyButton } from "../button/weekly-button/WeeklyButton";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

상대 경로 import는 절대 경로로 바꿔주세요.

"../../lib", "../button/weekly-button/WeeklyButton" 모두 상대 경로 import입니다.

As per path instructions, **/*.{ts,tsx}: "절대 경로 import 사용 (상대 경로 ../../ 지양)".

📦 절대 경로 import 예시
-import { cn } from "../../lib";
-import { WeeklyButton } from "../button/weekly-button/WeeklyButton";
+import { cn } from "`@/lib`";
+import { WeeklyButton } from "`@/components/button/weekly-button/WeeklyButton`";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { cn } from "../../lib";
import { WeeklyButton } from "../button/weekly-button/WeeklyButton";
import { cn } from "`@/lib`";
import { WeeklyButton } from "`@/components/button/weekly-button/WeeklyButton`";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/timo-design-system/src/components/calendar/Calendar.tsx` around
lines 3 - 4, Replace the relative imports in Calendar with absolute imports by
updating the `cn` and `WeeklyButton` imports to use the project’s absolute path
alias instead of `../../lib` and `../button/weekly-button/WeeklyButton`. Keep
the `Calendar` component unchanged otherwise and ensure the new import paths
resolve to the same modules via the existing absolute path convention.

Source: Path instructions

Comment thread packages/timo-design-system/src/components/calendar/Calendar.tsx
Comment thread packages/timo-design-system/src/components/calendar/Calendar.tsx
Comment on lines +64 to +66
const [visibleMonth, setVisibleMonth] = useState(
defaultMonth ?? value ?? new Date(),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

visibleMonth가 controlled value 변경을 따라가지 않아요.

useState(defaultMonth ?? value ?? new Date())는 마운트 시 한 번만 평가됩니다. 이후 부모가 value를 다른 달의 날짜로 바꿔도 visibleMonth는 그대로 남아 표시되는 달이 갱신되지 않습니다. Storybook 데모(Calendar.stories.tsx)처럼 value를 controlled로 관리하는 소비 패턴을 고려하면, 외부에서 값이 바뀌는 경우를 지원해야 할 가능성이 높습니다.

useEffectvalue 변경 시 visibleMonth를 동기화하거나, 최소한 이 제약을 CalendarProps 문서에 명시하는 것을 권장드려요.

🔄 value 변경 시 visibleMonth 동기화 제안
+import { useEffect, useState } from "react";
-import { useState } from "react";

 export const Calendar = ({ value, defaultMonth, onChange, className }: CalendarProps) => {
   const [visibleMonth, setVisibleMonth] = useState(
     defaultMonth ?? value ?? new Date(),
   );
+  useEffect(() => {
+    if (value) {
+      setVisibleMonth(value);
+    }
+  }, [value]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/timo-design-system/src/components/calendar/Calendar.tsx` around
lines 64 - 66, The visibleMonth state in Calendar is initialized only once with
useState(defaultMonth ?? value ?? new Date()), so it does not follow later
controlled value updates. Update Calendar so visibleMonth stays in sync when the
value prop changes, for example by adding a useEffect in Calendar.tsx that
watches value and updates setVisibleMonth accordingly while preserving
defaultMonth behavior. Use the Calendar and visibleMonth state in
packages/timo-design-system/src/components/calendar/Calendar.tsx to locate the
fix.

Comment thread packages/timo-design-system/src/components/calendar/Calendar.tsx
Comment thread packages/timo-design-system/src/components/calendar/Calendar.tsx Outdated
Comment on lines +87 to +91
<WeeklyButton
variant="left"
onClick={() => moveMonth(-1)}
className="absolute top-0 left-0"
/>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

캘린더 버튼에서도 WeeklyButton이 쓰여서, 위클리 버튼 자체 컴포넌트명을 변경하는 게 어떨까 싶어요!

아이콘 기반이니까 ChevronButton 정도가 어떨까요?

Comment thread packages/timo-design-system/src/components/calendar/Calendar.tsx
Comment thread packages/timo-design-system/src/components/index.ts Outdated
Comment thread packages/timo-design-system/src/components/calendar/Calendar.tsx Outdated
Co-authored-by: 김민아 <kmina121777@naver.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/timo-design-system/src/components/calendar/Calendar.tsx (1)

88-107: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

moveMonth가 정의되지 않아 월 이동 버튼이 동작하지 않아요. 🫠

함수명을 moveMonth에서 handleMoveMonth로 리네임하셨지만, 두 WeeklyButtononClick 호출 site는 여전히 moveMonth를 참조하고 있습니다. 버튼 클릭 시 ReferenceError: moveMonth is not defined가 발생합니다.

정적 분석에서도 'handleMoveMonth' is assigned a value but never used 경고가 나오고 있어요.

🔧 호출 site 수정 제안
         <WeeklyButton
           variant="left"
-          onClick={() => moveMonth(-1)}
+          onClick={() => handleMoveMonth(-1)}
           className="absolute top-0 left-0"
         />
         <WeeklyButton
           variant="right"
-          onClick={() => moveMonth(1)}
+          onClick={() => handleMoveMonth(1)}
           className="absolute top-0 right-0"
         />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/timo-design-system/src/components/calendar/Calendar.tsx` around
lines 88 - 107, The month navigation buttons in Calendar are still calling the
old moveMonth handler, so the renamed handler is unused and clicks throw a
ReferenceError. Update the onClick handlers on both WeeklyButton instances in
Calendar.tsx to call handleMoveMonth with the correct direction values, and
ensure the component consistently uses the renamed handler instead of moveMonth.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/timo-design-system/src/components/calendar/Calendar.tsx`:
- Around line 88-107: The month navigation buttons in Calendar are still calling
the old moveMonth handler, so the renamed handler is unused and clicks throw a
ReferenceError. Update the onClick handlers on both WeeklyButton instances in
Calendar.tsx to call handleMoveMonth with the correct direction values, and
ensure the component consistently uses the renamed handler instead of moveMonth.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0ba05bbb-fd6d-452e-a346-c611ee9a9518

📥 Commits

Reviewing files that changed from the base of the PR and between 0c11d89 and 3104604.

📒 Files selected for processing (1)
  • packages/timo-design-system/src/components/calendar/Calendar.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/timo-design-system/src/components/calendar/Calendar.tsx (2)

95-95: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

🚨 moveMonth가 정의되지 않았어요 — 런타임 ReferenceError 발생!

Line 82에서 handleMoveMonth로 정의했지만, Line 95와 110에서는 moveMonth를 호출하고 있습니다. moveMonth는 스코프에 존재하지 않아 클릭 시 ReferenceError: moveMonth is not defined가 발생합니다. 이는 파이프라인 Type Check 실패의 원인이기도 합니다.

🔧 제안: `handleMoveMonth`로 통일
         <WeeklyButton
           variant="left"
-          onClick={() => moveMonth(-1)}
+          onClick={() => handleMoveMonth(-1)}
           className="absolute top-0 left-0"
         />
         <WeeklyButton
           variant="right"
-          onClick={() => moveMonth(1)}
+          onClick={() => handleMoveMonth(1)}
           className="absolute top-0 right-0"
         />

Also applies to: 110-110

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/timo-design-system/src/components/calendar/Calendar.tsx` at line 95,
`Calendar` has a handler name mismatch: `handleMoveMonth` is defined, but the
click handlers still call `moveMonth`, which causes a runtime ReferenceError.
Update the `Calendar` component so the month navigation buttons consistently use
`handleMoveMonth` everywhere it is referenced, including both previous/next
controls, and keep the naming aligned with the existing function definition.

Source: Pipeline failures


115-115: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

grid-rows-6는 6주 달(42칸)에서 레이아웃이 넘칩니다.

요일 헤더 7칸(1행) + 날짜 셀이 같은 grid 안에 있습니다. calendarCellCount가 42일 때 총 49개 아이템 = 7행이 필요하지만 grid-rows-6로 고정되어 있어 7번째 행이 암시적 행으로 처리됩니다. 이로 인해 6주 달의 마지막 주가 의도한 높이로 렌더되지 않을 수 있습니다.

요일 헤더를 별도 grid로 분리하거나, grid-rows-7로 변경하는 것을 권장합니다.

📐 제안: 요일 헤더 분리
-      <div className={cn("grid grid-cols-7 grid-rows-6 gap-x-1 gap-y-1.5")}>
-        {WEEKDAYS.map((weekday, index) => (
-          <div
-            key={`${weekday}-${index}`}
-            className="typo-headline-b-16 text-timo-gray-900 flex items-center justify-center"
-          >
-            {weekday}
-          </div>
-        ))}
-
-        {calendarDates.map((calendarDate) => {
+      <div className="mb-1.5 grid grid-cols-7 gap-x-1">
+        {WEEKDAYS.map((weekday, index) => (
+          <div
+            key={`${weekday}-${index}`}
+            className="typo-headline-b-16 text-timo-gray-900 flex items-center justify-center"
+          >
+            {weekday}
+          </div>
+        ))}
+      </div>
+
+      <div className={cn("grid grid-cols-7 grid-rows-6 gap-x-1 gap-y-1.5")}>
+        {calendarDates.map((calendarDate) => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/timo-design-system/src/components/calendar/Calendar.tsx` at line
115, The Calendar grid uses a fixed grid-rows-6 while the same grid contains
both the 7-day header and all date cells, so 6-week months can overflow into an
implicit 7th row. Update the layout in Calendar to either separate the weekday
header from the date grid or change the container to use grid-rows-7, and keep
the logic around calendarCellCount aligned with the rendered row count.
♻️ Duplicate comments (2)
packages/timo-design-system/src/components/index.ts (1)

35-35: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

WeeklyButton export명과 파일명 ChevronButton이 불일치합니다.

Calendar.tsx 리뷰에서 통합 제안드린 rename과 동일한 이슈입니다. export명도 ChevronButton으로 맞춰주세요.

🔧 제안
-export { WeeklyButton } from "./button/chevron-button/ChevronButton";
+export { ChevronButton } from "./button/chevron-button/ChevronButton";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/timo-design-system/src/components/index.ts` at line 35, The
component export name in the index barrel is mismatched with the actual
component/file name, so update the export in the components index to use
ChevronButton instead of WeeklyButton. Keep the exported symbol aligned with the
existing ChevronButton component from button/chevron-button/ChevronButton so
imports and naming stay consistent across the design system.
packages/timo-design-system/src/components/button/chevron-button/ChevronButton.stories.tsx (1)

1-6: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Storybook title은 ChevronButton인데 import는 WeeklyButton이에요.

title과 컴포넌트명이 불일치하면 Storybook에서 혼란이 발생합니다. Calendar.tsx에서 제안드린 전체 rename을 적용하면 자연스럽게 해결됩니다.

🔧 제안
-import { WeeklyButton } from "./ChevronButton";
+import { ChevronButton } from "./ChevronButton";

이하 WeeklyButtonChevronButton 치환

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/timo-design-system/src/components/button/chevron-button/ChevronButton.stories.tsx`
around lines 1 - 6, The Storybook story is still importing and referencing
WeeklyButton while the story title and component are ChevronButton, so update
ChevronButton.stories.tsx to use ChevronButton consistently. Replace the
WeeklyButton import and any related story metadata/args references with
ChevronButton so the story name, imported symbol, and component identity all
match.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/timo-design-system/src/components/calendar/Calendar.tsx`:
- Line 4: Rename the remaining WeeklyButton symbols to ChevronButton so the
component, exports, and types all match the new file/story naming. Update the
component definition in ChevronButton-related code, including WeeklyButtonProps
and WeeklyButtonVariantTypes to ChevronButtonProps and
ChevronButtonVariantTypes, and adjust any exports/imports such as the one used
in Calendar.tsx and the barrel index.ts so they reference ChevronButton
consistently.

---

Outside diff comments:
In `@packages/timo-design-system/src/components/calendar/Calendar.tsx`:
- Line 95: `Calendar` has a handler name mismatch: `handleMoveMonth` is defined,
but the click handlers still call `moveMonth`, which causes a runtime
ReferenceError. Update the `Calendar` component so the month navigation buttons
consistently use `handleMoveMonth` everywhere it is referenced, including both
previous/next controls, and keep the naming aligned with the existing function
definition.
- Line 115: The Calendar grid uses a fixed grid-rows-6 while the same grid
contains both the 7-day header and all date cells, so 6-week months can overflow
into an implicit 7th row. Update the layout in Calendar to either separate the
weekday header from the date grid or change the container to use grid-rows-7,
and keep the logic around calendarCellCount aligned with the rendered row count.

---

Duplicate comments:
In
`@packages/timo-design-system/src/components/button/chevron-button/ChevronButton.stories.tsx`:
- Around line 1-6: The Storybook story is still importing and referencing
WeeklyButton while the story title and component are ChevronButton, so update
ChevronButton.stories.tsx to use ChevronButton consistently. Replace the
WeeklyButton import and any related story metadata/args references with
ChevronButton so the story name, imported symbol, and component identity all
match.

In `@packages/timo-design-system/src/components/index.ts`:
- Line 35: The component export name in the index barrel is mismatched with the
actual component/file name, so update the export in the components index to use
ChevronButton instead of WeeklyButton. Keep the exported symbol aligned with the
existing ChevronButton component from button/chevron-button/ChevronButton so
imports and naming stay consistent across the design system.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ad192f05-55e5-4428-96f0-a72f2bb9b41d

📥 Commits

Reviewing files that changed from the base of the PR and between 3104604 and 297fa69.

📒 Files selected for processing (5)
  • packages/timo-design-system/src/components/button/chevron-button/ChevronButton.stories.tsx
  • packages/timo-design-system/src/components/button/chevron-button/ChevronButton.tsx
  • packages/timo-design-system/src/components/calendar/Calendar.stories.tsx
  • packages/timo-design-system/src/components/calendar/Calendar.tsx
  • packages/timo-design-system/src/components/index.ts

import { useState } from "react";

import { cn } from "../../lib";
import { WeeklyButton } from "../button/chevron-button/ChevronButton";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

WeeklyButtonChevronButton 이름 변경이 완료되지 않았어요.

파일명은 ChevronButton으로 바뀌었고 Storybook title도 ChevronButton으로 갱신되었지만, 컴포넌트 자체는 여전히 WeeklyButton입니다. 파일명과 export명이 불일치하면 사용자가 헷갈립니다. kimminna님의 이전 리뷰에서도 ChevronButton으로 변경을 제안하셨던 부분입니다.

컴포넌트명, export명, 타입명(WeeklyButtonPropsChevronButtonProps, WeeklyButtonVariantTypesChevronButtonVariantTypes)까지 모두 ChevronButton으로 통일하는 것을 권장합니다.

♻️ 전체 rename 제안

ChevronButton.tsx 내부:

-export type WeeklyButtonVariantTypes = "left" | "right";
+export type ChevronButtonVariantTypes = "left" | "right";

-const WEEKLY_BUTTON_ICON: Record<WeeklyButtonVariantTypes, ReactNode> = {
+const CHEVRON_BUTTON_ICON: Record<ChevronButtonVariantTypes, ReactNode> = {

-const WEEKLY_BUTTON_ARIA_LABEL: Record<WeeklyButtonVariantTypes, string> = {
+const CHEVRON_BUTTON_ARIA_LABEL: Record<ChevronButtonVariantTypes, string> = {

-export interface WeeklyButtonProps {
+export interface ChevronButtonProps {

-export const WeeklyButton = ({ ... }: WeeklyButtonProps) => {
+export const ChevronButton = ({ ... }: ChevronButtonProps) => {

index.ts:

-export { WeeklyButton } from "./button/chevron-button/ChevronButton";
+export { ChevronButton } from "./button/chevron-button/ChevronButton";

Calendar.tsx:

-import { WeeklyButton } from "../button/chevron-button/ChevronButton";
+import { ChevronButton } from "../button/chevron-button/ChevronButton";

Also applies to: 125-160

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/timo-design-system/src/components/calendar/Calendar.tsx` at line 4,
Rename the remaining WeeklyButton symbols to ChevronButton so the component,
exports, and types all match the new file/story naming. Update the component
definition in ChevronButton-related code, including WeeklyButtonProps and
WeeklyButtonVariantTypes to ChevronButtonProps and ChevronButtonVariantTypes,
and adjust any exports/imports such as the one used in Calendar.tsx and the
barrel index.ts so they reference ChevronButton consistently.

@github-actions github-actions Bot added the ⏰ Timo-web Timo 웹 서비스 label Jul 8, 2026
@yumin-kim2 yumin-kim2 merged commit 47e91db into develop Jul 8, 2026
12 checks passed
@yumin-kim2 yumin-kim2 deleted the feat/ui/107-calendar-component branch July 8, 2026 13:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 새로운 기능(기능성) 구현 ⌚ Timo-Design-system Timo 디자인 시스템 ⏰ Timo-web Timo 웹 서비스 ♣️ 유민 유민양

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 공통 Calendar 컴포넌트 구현

3 participants